import FoodMod, { IFood } from "../model/FoodMod";
import { RandUtil } from "../../common/game/util/RandUtil";
import SnakeMod from "../model/SnakeMod";
import { ClientEvent } from "../event/ClinetEvent";
import BaseView from "../core/mvc/BaseView";

const { ccclass, property } = cc._decorator;
const ru = RandUtil
const et = ClientEvent.Type

@ccclass
export default class FoodView extends BaseView {

    @property(cc.Prefab)
    foodPre: cc.Node = null

    /** 食物实例组 */
    foods: Map<number, {
        node: cc.Node,
        width: number,
        spawning: boolean,
        eating: boolean,
        clearing: boolean,
        eater: { x: number, y: number },
    }> = new Map()

    /** 生成动画平滑度 */
    spawnSmoothing: number = 6.66
    /** 清理动画平滑度 */
    clearSmoothing: number = 6.66
    /** 被吃动画平滑度 */
    eatSmoothing: number = 6.66

    foodPool: cc.NodePool = null

    _mod: FoodMod

    eatFood(id: number, eater: { x: number, y: number }) {
        if (eater) {
            let food = this.foods.get(id)
            if (food) {
                food.clearing = true
                food.eating = true
                food.eater = eater
            }
        }
        this.clear(id)
    }

    onLoad() {
        this.foodPool = new cc.NodePool()

        this._mod = FoodMod.ins
        let ed = this._mod.ed
        ed.on(et.FOOD_LOAD, this, e => {
            e.model.extractLoadFoods().forEach(food => {
                this.spawnFood(food)
            })
        })
        ed.on(et.FOOD_UNLOAD, this, e => {
            e.model.extractUnloadFoodMap().forEach((eaterId, foodId) => {
                if (eaterId) {
                    this.eatFood(foodId, SnakeMod.ins.getSnakeNode(eaterId))
                } else {
                    this.clear(foodId)
                }
            })
        })
    }

    /** 生成食物动画 */
    anim(dt: number) {
        this.foods.forEach((f, id) => {
            //清理动画
            if (f.clearing) {
                f.spawning = false
                f.node.scale = cc.misc.lerp(f.node.scale, -0.233, dt * this.clearSmoothing)
                //被吃动画
                if (f.eating) {
                    f.node.x = cc.misc.lerp(f.node.x, f.eater.x, dt * this.eatSmoothing)
                    f.node.y = cc.misc.lerp(f.node.y, f.eater.y, dt * this.eatSmoothing)
                }
                if (f.node.scale < 0) {
                    this.delFood(id)
                    f.eater = null
                }
            }

            //生成动画
            if (f.spawning) {
                f.node.scale = cc.misc.lerp(f.node.scale, f.width + 0.233, dt * this.clearSmoothing)
                if (f.node.scale > f.width) {
                    f.node.scale = f.width
                    f.spawning = false
                }
            }
        })
    }

    delFood(id: number) {
        let food = this.foods.get(id)
        this.foods.delete(id)
        this.delFoodNode(food.node)
    }

    clear(id: number) {
        let food = this.foods.get(id)
        if (food) {
            food.clearing = true
        }
    }

    getFoodNode() {
        return this.foodPool.get() || cc.instantiate(this.foodPre)
    }

    delFoodNode(node: cc.Node) {
        this.foodPool.put(node)
    }

    spawnFood(food: IFood) {
        let ins = this.foods.get(food.id)
        if (ins) {
            ins.width = food.w
            ins.spawning = true
            ins.eating = false
            ins.clearing = false
            ins.eater = null
        } else {
            ins = {
                node: this.getFoodNode(),
                width: food.w,
                spawning: true,
                eating: false,
                clearing: false,
                eater: null
            }
            let node = ins.node
            node.parent = this.node
            node.name = food.id.toString()
            node.x = food.x
            node.y = food.y
            node.scale = 0
            node.color = cc.color(food.color || ru.randColor())
        }

        this.foods.set(food.id, ins)
        return food
    }

    update(dt) {
        this.anim(dt)
    }
}